package selectors;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map.Entry;

import strategies.Strategy;

import base.Environment;

import agents.Agent;
import agents.AverageUtility;

import static base.Environment.Configurations.*;

public class RouletteStrategySelector extends StrategySelector {

	protected double minUsagesFactor;
	
	
	public RouletteStrategySelector(Environment env) {
		minUsagesFactor = env.getDouble(MIN_USAGES_FACTOR);
	}
	
	
	@Override
	public Strategy selectStrategy(Agent agent) {
		
		Strategy strategy = null;
		double max = Double.NEGATIVE_INFINITY;
		int steps = 0;
		
		for (Entry<Strategy, AverageUtility> entry : agent.getStrategies().entrySet())
			if (entry.getValue().getAverageUtility() > max) {
				strategy = entry.getKey();
				max = entry.getValue().getAverageUtility();
				steps = entry.getValue().getSteps();
			}
		
		// weak!
		if (max < 0d)
			return strategy;
		
		if (max == 0d) {
			LinkedList<Strategy> list = new LinkedList<Strategy>();
			list.addAll(agent.getStrategies().keySet());
			return list.get((int) (Math.random() * list.size()));
		}
		
		double sum = 0d;
		LinkedHashMap<Strategy, Double> roulette = new LinkedHashMap<Strategy, Double>();
		
		for (Entry<Strategy, AverageUtility> entry : agent.getStrategies().entrySet()) {
			
				double share;
				if (entry.getValue().getSteps() < steps * minUsagesFactor &&
					entry.getValue().getAverageUtility() < max)
					share = max;
				else
					share = entry.getValue().getAverageUtility();
				
				if (share > 1d)
					share *= share;
				roulette.put(entry.getKey(), share);
				sum += share;
			}
		
		double r = Math.random() * sum;
		for (Strategy s : roulette.keySet())
			if (r < roulette.get(s))
				return s;
			else
				r -= roulette.get(s);
		
		// must compile
		return strategy;
	}
}
